# -*- coding: utf-8 -*-
# created on 2016/12/12

from mathsolver.functions.hanshu.hengchengli_leixing import FxMin, FxMax
from mathsolver.functions.hanshu.helper import reverse_op
from mathsolver.functions.base import BaseFunction, BaseIneq


class XxXingDingYiZuiZhi(BaseFunction):
    """计算 'xx'型定义 的输出中包含的 fx_min, fx_max 的最值
    输入: (BaseIneq([fx_min, op, fx_max]), )
    输出: 原始输入，和计算出的最值 BaseIneq([jisuan_fx_min, op, jisuan_fx_max])"""

    def solver(self, *args):

        def jisuan_zuizhi(arg):
            from mathsolver.functions.hanshu.zuizhi_new import MinValue, MaxValue
            if isinstance(arg, FxMin):
                step_solver = MinValue(self.known).solver(arg.BaseFunc_obj, arg.def_interval)
                self.steps.extend(step_solver.steps)
                res = step_solver.output[0].value
                return res
            elif isinstance(arg, FxMax):
                step_solver = MaxValue(self.known).solver(arg.BaseFunc_obj, arg.def_interval)
                self.steps.extend(step_solver.steps)
                res = step_solver.output[0].value
                return res
            else:
                return arg

        ineq = args[0][0]
        left, op, right = [jisuan_zuizhi(arg) for arg in ineq.value]

        self.label.add("求函数值域/最值")
        self.output.extend([ineq, BaseIneq([left, op, right])])
        return self


def _not_minmax(arg):
    return not isinstance(arg, (FxMin, FxMax))


def _is_min(arg):
    return isinstance(arg, FxMin)


def _is_max(arg):
    return isinstance(arg, FxMax)


def _minmax_reacheable(arg):
    return arg[1][1]


def _get_limit(arg):
    return arg[0]


def _has_canshu(arg):
    return isinstance(arg, dict)


op_group1 = {'>', '>='}
op_group2 = {'<', '<='}


def _linjie_no_canshu(ineq0, ineq1):
    """不等式成立临界状态 (不含参数)
    输入 ([BaseIneq_original, BaseIneq_calculated],)"""

    (left0, op, right0), (left1, op, right1) = ineq0.value, ineq1.value

    # case 1
    if _is_min(left0) and op in op_group1 and _not_minmax(right0):
        if not _minmax_reacheable(left1):
            op = '>='

        res = [_get_limit(left1), op, right1]

    # case 2
    elif _is_max(left0) and op in op_group2 and _not_minmax(right0):
        if not _minmax_reacheable(left1):
            op = '<='
        res = [_get_limit(left1), op, right1]

    # case 3
    elif _is_min(left0) and op in op_group2 and _not_minmax(right0):
        if not _minmax_reacheable(left1):
            op = '<'
        res = [_get_limit(left1), op, right1]

    # case 4
    elif _is_max(left0) and op in op_group1 and _not_minmax(right0):
        if not _minmax_reacheable(left1):
            op = '>'
        res = [_get_limit(left1), op, right1]

    # case 5
    elif _is_min(left0) and op == '>=' and _is_max(right0):
        res = [_get_limit(left1), '>=', _get_limit(right1)]

    # case 6
    elif _is_min(left0) and op == '>' and _is_max(right0):
        if _minmax_reacheable(left1) and _minmax_reacheable(right1):
            op = '>'
        else:
            op = '>='

        res = [_get_limit(left1), op, _get_limit(right1)]

    # case 7
    elif _is_max(left0) and op == '>=' and _is_min(right0):
        if _minmax_reacheable(left1) and _minmax_reacheable(right1):
            op = '>='
        else:
            op = '>'

        res = [_get_limit(left1), op, _get_limit(right1)]

    # case 8
    elif _is_max(left0) and op == '>' and _is_min(right0):
        res = [_get_limit(left1), '>', _get_limit(right1)]

    # case 9
    elif _is_min(left0) and op == '>=' and _is_min(right0):
        if _minmax_reacheable(left1) and not _minmax_reacheable(right1):
            op = '>'
        res = [_get_limit(left1), op, _get_limit(right1)]

    # case 10
    elif _is_min(left0) and op == '>' and _is_min(right0):
        if not _minmax_reacheable(left1) and _minmax_reacheable(right1):
            op = '>='
        res = [_get_limit(left1), op, _get_limit(right1)]

    # case 11
    elif _is_max(left0) and op == '<=' and _is_max(right0):
        if _minmax_reacheable(left1) and not _minmax_reacheable(right1):
            op = '<'
        res = [_get_limit(left1), op, _get_limit(right1)]

    # case 12
    elif _is_max(left0) and op == '<' and _is_max(right0):
        if not _minmax_reacheable(left1) and _minmax_reacheable(right1):
            op = '<='
        res = [_get_limit(left1), op, _get_limit(right1)]

    else:
        try:
            # f < g => g > f
            ineq0_new = BaseIneq((right0, reverse_op(op), left0))
            ineq1_new = BaseIneq((right1, reverse_op(op), left1))
            res = _linjie_no_canshu(ineq0_new, ineq1_new)
        except Exception:
            raise NotImplementedError('cannot handle relation')

    return res


def hengchengli_lingjie(ineq0, ineq1):
    """hs031. 不等式成立临界状态 （含参数、不含参数）
    输入 ([BaseIneq_original, BaseIneq_calculated],)
    """

    left1, op, right1 = ineq1.value

    # 如果两边都含有参数
    if _has_canshu(left1) and _has_canshu(right1):

        # 如果 ineq1 是 [{(0, oo): [k - 2, (1, True)]}, '>=', {(0, oo): [k/3, (1, True)]}] 的格式
        if left1.keys() == right1.keys() and len(left1.keys()) == 1:

            key_qujian = left1.keys()[0]
            left1_zuizhi = left1[key_qujian]
            righ1_zuizhi = right1[key_qujian]
            res = _linjie_no_canshu(ineq0, BaseIneq([left1_zuizhi, op, righ1_zuizhi]))

        else:
            raise NotImplementedError('两边都含有参数，暂时不可解')

    # 如果左边含有参数
    elif _has_canshu(left1):
        res = []
        for _canshu_range, _zuizhi in left1.items():
            case = _linjie_no_canshu(ineq0, BaseIneq([_zuizhi, op, right1]))
            res.append([_canshu_range, case])

    # 如果右边含有参数
    elif _has_canshu(right1):
        res = []
        for _canshu_range, _zuizhi in right1.items():
            case = _linjie_no_canshu(ineq0, BaseIneq([left1, op, _zuizhi]))
            res.append([_canshu_range, case])

    # 不含参数的情况
    else:
        res = _linjie_no_canshu(ineq0, ineq1)

    return res
